package com.fucking.great.context.common.template;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.fucking.great.context.exception.DevelopmentEncodedException;

import java.io.File;
import java.io.OutputStream;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class TemplateComponent {
    //
    private static final Map<TemplateConfig,TemplateComponent> SIGNLE_MAP =new ConcurrentHashMap<>();
    //
    private final TemplateConfig config;
    private final TemplateEngine templateEngine;

    private TemplateComponent(TemplateConfig config, TemplateEngine templateEngine) {
        this.config = config;
        this.templateEngine = templateEngine;
    }

    /**
     * 单例化获得
     * @param config
     * @return
     */
    public final static TemplateComponent getInstance(TemplateConfig config){
        TemplateComponent templateComponent = SIGNLE_MAP.computeIfAbsent(config, key -> {
            TemplateEngine engine = TemplateUtil.createEngine(key);
            return new TemplateComponent(key,engine);
        });
        return templateComponent;
    }


    /**
     * 获得不同模式。
     * @param resourceMode
     * @return
     */
    public TemplateComponent getInstance(TemplateConfig.ResourceMode resourceMode){
        Validator.validateNull(resourceMode,"传入的ResourceMode为空");
        return copyInstance(null,resourceMode,null,null);
    }

    /**
     * @see TemplateComponent#copyInstance(java.lang.String, cn.hutool.extra.template.TemplateConfig.ResourceMode, java.nio.charset.Charset, java.lang.Class)
     * @param path
     * @param resourceMode
     * @return
     */
    public TemplateComponent copyInstance(String path,TemplateConfig.ResourceMode resourceMode){
        return copyInstance(path,resourceMode,null,null);
    }
    /**
     * 复制当前对象的配置当做默认配置，并设置不为null的配置项，生成新的TemplateComponent
     * @param path
     * @param resourceMode
     * @param charset
     * @param customEngine
     * @return
     */
    public TemplateComponent copyInstance(String path,TemplateConfig.ResourceMode resourceMode,Charset charset,Class<? extends TemplateEngine> customEngine){
        TemplateConfig configCopy = new TemplateConfig();
        BeanUtil.copyProperties(this.getConfig(),configCopy);
        //
        if (StrUtil.isNotBlank(path)) {
            configCopy.setPath(path);
        }
        //
        if(resourceMode != null ){
            configCopy.setResourceMode(resourceMode);
        }
        //
        if(charset != null){
            configCopy.setCharset(charset);
        }
        // customEngine
        if (customEngine != null){
            configCopy.setCustomEngine(customEngine);
        }
        //
        return getInstance(configCopy);
    }

    /**
     * 找到模板并与绑定参数融合,并输出
     * @see Template
     * @see TemplateEngine
     * @param resource 获取模板  {@link cn.hutool.extra.template.TemplateEngine#getTemplate}
     * @param bindingMap
     * @param writer
     */
    public void render(String resource,Map<?, ?> bindingMap, Writer writer) {
        Template template = templateEngine.getTemplate(resource);
        template.render(bindingMap, writer);
    }

    /**
     * 找到模板并与绑定参数融合,并输出
     * @see Template
     * @see TemplateEngine
     * @param resource 获取模板  {@link cn.hutool.extra.template.TemplateEngine#getTemplate}
     * @param bindingMap
     * @param out
     */
    public void render(String resource,Map<?, ?> bindingMap, OutputStream out) {
        Template template = templateEngine.getTemplate(resource);
        template.render(bindingMap, out);
    }

    /**
     * 找到模板并与绑定参数融合,并输出
     * @see Template
     * @see TemplateEngine
     * @param resource 获取模板  {@link cn.hutool.extra.template.TemplateEngine#getTemplate}
     * @param bindingMap
     * @param file
     */
    public void render(String resource,Map<?, ?> bindingMap, File file) {
        Template template = templateEngine.getTemplate(resource);
        template.render(bindingMap, file);
    }

    /**
     * 找到模板并与绑定参数融合,并输出
     * @see Template
     * @see TemplateEngine
     * @param resource 获取模板  {@link cn.hutool.extra.template.TemplateEngine#getTemplate}
     * @param bindingMap
     * @return
     */
    public String render(String resource,Map<?, ?> bindingMap) {
        Template template = templateEngine.getTemplate(resource);
        return template.render(bindingMap);
    }


    ////////////////////////////////////////
    //
    ////////////////////////////////////////

    /**
     * 这个设置了,不会生效,只做展示。
     */
    public TemplateConfig getConfig() {
        return config;
    }

    public TemplateEngine getTemplateEngine() {
        return templateEngine;
    }
}
